package com.zhiwei.msf.gateway.config;

import com.alibaba.fastjson.JSON;
import com.zhiwei.msf.gateway.constants.GatewayConstant;
import com.zhiwei.msf.gateway.service.WhiteListService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ZHIWEI.YANG
 * @time 2019/12/9 - 21:36
 * @decription 自定义资源权限
 */
@Slf4j
@Component
@RefreshScope
public class GatewaySecurityMetadataSource implements FilterInvocationSecurityMetadataSource, ApplicationListener<RefreshScopeRefreshedEvent> {

    private final Map<RequestMatcher, Collection<ConfigAttribute>> urlPathMatcherMap = new ConcurrentHashMap<>();

    @Autowired
    private WhiteListService whiteListService;

    /**
     * object 需授权操作的对象： 例如网址
     *
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest httpServletRequest = filterInvocation.getRequest();
        Set<ConfigAttribute> allAttributes = new HashSet<>();
        this.refresh();
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : urlPathMatcherMap.entrySet()) {
            if (entry.getKey().matches(httpServletRequest)) {
                allAttributes.addAll(entry.getValue());
            }
        }
        return allAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> configAttributes = new HashSet<>();
        urlPathMatcherMap.forEach((key, value) -> configAttributes.addAll(value));
        return configAttributes;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * 白名单刷新
     */
    private Map<RequestMatcher, Collection<ConfigAttribute>> refresh() {
        List<String> whiteUrlList = whiteListService.queryValidWhiteList();
        log.info("白名单URL列表：{}", JSON.toJSONString(whiteUrlList));
        Set<String> intimePathSet = new HashSet<>();
        if (!CollectionUtils.isEmpty(whiteUrlList)) {
            for (String url : whiteUrlList) {
                intimePathSet.add(url);
                AntPathRequestMatcher homeAntPathRequestMatcher = new AntPathRequestMatcher(url);
                urlPathMatcherMap.put(homeAntPathRequestMatcher, SecurityConfig.createList(GatewayConstant.WHITE_LIST_ROLE));
            }
        }
        Collection<Object> invalidWhitePathSet = CollectionUtils.subtract(urlPathMatcherMap.keySet(), intimePathSet);
        urlPathMatcherMap.forEach((key, value) -> {
            if (invalidWhitePathSet.contains(key)) {
                urlPathMatcherMap.remove(key);
            }
        });
        return urlPathMatcherMap;
    }

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        this.refresh();
    }
}